package co.edu.udea.iw.prestamos.bl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

import java.util.Date;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import co.edu.udea.iw.prestamos.modelo.dao.DispositivoDAO;
import co.edu.udea.iw.prestamos.modelo.dao.EstadoPrestamoDAO;
import co.edu.udea.iw.prestamos.modelo.dao.PrestamoDAO;
import co.edu.udea.iw.prestamos.modelo.dao.UsuarioDAO;
import co.edu.udea.iw.prestamos.modelo.dto.Dispositivo;
import co.edu.udea.iw.prestamos.modelo.dto.EstadoPrestamo;
import co.edu.udea.iw.prestamos.modelo.dto.Prestamo;
import co.edu.udea.iw.prestamos.modelo.dto.PrestamoList;
import co.edu.udea.iw.prestamos.modelo.dto.Respuesta;
import co.edu.udea.iw.prestamos.modelo.dto.Usuario;
import co.edu.udea.iw.prestamos.util.exception.DatabaseException;
import co.edu.udea.iw.prestamos.util.exception.RegistryNotFoundException;

/**
 * Se realizan Pruebas de Integracion para la logica de negocio de prestamos de 
 * dispositivos.
 * 
 * Se verifica que el contexto, el mapeo de los daos y las inyecciones usando 
 * Spring funcionan correctamente.
 * 
 * En esta prueba de integracion se prueban los DAO's {@link UsuarioDAO},
 * {@link PrestamoDAO}, {@link EstadoPrestamoDAO}, {@link DispositivoDAO}. Ademas
 * se prueba el BL {@link PrestamoBL}
 * @author Dave Rivera <daverivera90@gmail.com>
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:configuracion.xml"})
@Transactional
public class PrestamoBLITest {

	/**
	 * Clase que se va a probar.
	 */
	@Autowired
	private PrestamoBL prestamoBL;
	
	@Autowired
	private UsuarioDAO usuarioDao;
	
	@Autowired
	private PrestamoDAO prestamoDao;
	
	@Autowired
	private EstadoPrestamoDAO estadoPrestamoDao;
	
	@Autowired
	private DispositivoDAO dispositivoDao;
	
	/**
	 * Prueba el comportamiento de PrestamoBL integrado, cuando se trata de registrar un
	 * préstamos pasando un objeto nulo.
	 */
	@Test
	public void debeFallarAlRegistrarPrestamoNulo() {
		// Teniendo
		Prestamo prestamo = null;
		
		// Cuando
		Respuesta respuesta = (Respuesta) prestamoBL.realizarPrestamo(prestamo);
		
		// Entonces
			// Debe retornar una respuesta de error.
		assertEquals(Respuesta.ERROR, respuesta.getTipo());
	}
	
	/**
	 * Prueba el comportamiento de PrestamoBL integrado, cuando se trata de registrar un
	 * préstamo con información completa.
	 * 
	 * @throws DatabaseException
	 * @throws RegistryNotFoundException
	 */
	@Test
	public void debeRealizarPrestamo()
		throws DatabaseException, RegistryNotFoundException {
		// Teniendo
		Prestamo prestamo = confPrestamo();
		
		// Cuando
		Respuesta respuesta = (Respuesta) prestamoBL.realizarPrestamo(prestamo);
		
		// Entonces
			// Debe retornar una respuesta existosa.
		assertEquals(Respuesta.SUCCESS, respuesta.getTipo());
	}

	/**
	 * Prueba el comportamiento de PrestamoBL integrado, cuando se trata de cambiar el
	 * estado de un préstamo.
	 * 
	 * @throws RegistryNotFoundException
	 */
	@Test
	public void debeCambiarEstadoDePrestamo() throws RegistryNotFoundException {
		// Teniendo
		int estadoPrestamo = 1;
		int prestamoId = 1;
		
		// Cuando
		Respuesta respuesta = (Respuesta) prestamoBL
			.cambiarEstado(prestamoId, estadoPrestamo);
		
		// Entonces
			// Debe retornar una respuesta exitosa.
		assertEquals(Respuesta.SUCCESS, respuesta.getTipo());
			// Debe cambiar correctamente el estado del préstamo con id 1.
		Prestamo p = prestamoDao.obtenerPorId(1);
		assertEquals((Integer)estadoPrestamo, p.getEstadoPrestamo().getId());
	}
	
	/**
	 * Prueba el comportamiento de PrestamoBL integrado, cuando se trata de obtener la
	 * lista de préstamos registrados.
	 */
	@Test
	public void debeRetornarListaDePrestamos() {
		// Cuando
		PrestamoList prestamos = (PrestamoList) prestamoBL.obtenerSolicitudes();
		
		// Entonces
			// Debe retornar una lista de préstamos.
		assertFalse(prestamos.isEmpty());
	}
	
	/**
	 * Configura un DTO {@link Prestamo}
	 * @return                           Objeto prestamo
	 * @throws RegistryNotFoundException No se lanza porque debe funcionar correctamente
	 */
	private Prestamo confPrestamo() throws RegistryNotFoundException{
		Usuario usuario = usuarioDao.obtenerPorId("1");
		Dispositivo dispositivo = dispositivoDao.obtenerPorId(1);
		EstadoPrestamo estado = estadoPrestamoDao.obtenerPorId(1);
		
		Prestamo prestamo = new Prestamo();
		prestamo.setUsuario(usuario);
		prestamo.setDispositivo(dispositivo);
		prestamo.setFechaSolicitud(new Date());
		prestamo.setFechaInicio(new Date());
		prestamo.setTiempo(8);
		prestamo.setEstadoPrestamo(estado);
		return prestamo;
	}
	
}
